"""
Case Type   : 系统内部使用工具
Case Name   : 执行gs_uninstall命令卸载数据库，不指定-l，且不在XML文件中配置gaussdbLogPath
Create At   : 2021/12/7
Owner       : @daiguatutu
Description :
    1.下载解压数据库安装包
    2.配置xml文件,不配置参数gaussdbLogPath
    3.创建初始用户并修改文件属组
    4.执行./gs_preinstall进行预安装
    5.执行gs_install安装1主1备
    6.执行gs_uninstall --delete-data
    7.清理环境
Expect      :
    1.下载解压成功
    2.配置成功
    3.创建成功
    4.预安装成功
    5.安装成功
    6.卸载成功，默认目录/var/log/gaussdb/用户名/om/下无日志文件。
    7.清理成功
History     :
    modified by @daiguatutu at 2022-10-31:修改因文件不存在导致的修改权限失败问题
    modified by @daiguatutu at 2022-11-15:优化用例,增加预安装超时时间
    modified by @daiguatutu at 2022-11-23:修改参数shared_buffers值,增加超时时间,避免性能问题安装失败
    modified by lonely-dance at 2025-3-24:优化用例安装包获取方式
"""
import os
import re
import time
import unittest

from yat.test import Node
from yat.test import macro

from testcase.utils.Common import Common
from testcase.utils.Common import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger

primary_sh = CommonSH('PrimaryDbUser')
Constant = Constant()


@unittest.skipIf(1 >= primary_sh.get_node_num(), '单机环境不执行')
class Tools(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pri_node = Node('PrimaryDbUser')
        self.pri_root_node = Node('PrimaryRoot')
        self.sta_node = Node('Standby1DbUser')
        self.sta_root_node = Node('Standby1Root')
        self.common = Common()
        self.u_name = 'gs_uninstall_0001'
        self.instance_path = macro.DB_INSTANCE_PATH
        for num in range(macro.DB_INSTANCE_PATH.count('/') - 1):
            self.instance_path = os.path.dirname(self.instance_path)
        self.dir_path = os.path.join(self.instance_path, self.u_name)
        self.package_path = os.path.join(self.dir_path, 'pkg')
        self.conf_path = os.path.join(self.dir_path, 'config')
        self.data_path = os.path.join(self.dir_path, 'cluster')
        self.xml_path = os.path.join(self.conf_path, 'primary_standby.xml')
        self.env_path = os.path.join(self.conf_path, 'env')
        self.script_path = os.path.join(self.package_path, 'script')

    def test_gs_uninstall(self):
        global log_path
        global log_file
        self.log.info('-----step1:下载解压数据库安装包 expect:下载解压成功-----')
        self.common.get_package(self.pri_root_node, self.pri_root_node, self.package_path, self.conf_path)

        self.log.info('-----查看主机名-----')
        pri_node_name = self.common.get_sh_result(self.pri_root_node,
                                                  "uname -n")
        self.assertIsNotNone(pri_node_name, 'pri_node_name获取失败')
        sta_node_name = self.common.get_sh_result(self.sta_root_node,
                                                  "uname -n")
        self.assertIsNotNone(sta_node_name, 'sta_node_name获取失败')
        self.log.info('-----查询系统未使用端口-----')
        port = self.common.get_not_used_port(self.pri_node)
        self.assertNotEqual(0, port, '端口获取失败')

        self.log.info('-----step2:配置xml文件,不配置gaussdbLogPath expect:配置成功-----')
        gaussdb_app_path = os.path.join(self.data_path, 'app')
        tmpmppdb_path = os.path.join(self.data_path, 'tmp')
        gaussdb_tool_path = os.path.join(self.data_path, 'tool')
        data_node1 = os.path.join(self.data_path, 'dn1')
        self.common.scp_file(self.pri_root_node, 'primary_standby.xml',
                             self.conf_path)
        xml_cmd = f"sed -i 's#v_nodeNames#{pri_node_name},{sta_node_name}" \
            f"#g' {self.xml_path};" \
            f"sed -i 's#v_gaussdbAppPath#{gaussdb_app_path}#g' " \
            f"{self.xml_path};" \
            f"sed -i '/gaussdbLogPath/d' {self.xml_path};" \
            f"sed -i 's#v_tmpMppdbPath#{tmpmppdb_path}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_gaussdbToolPath#{gaussdb_tool_path}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_corePath#{macro.DB_CORE_PATH}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_db_host#{self.pri_node.db_host}," \
            f"{self.sta_node.db_host}#g' {self.xml_path};" \
            f"sed -i 's#v_pri_nodeNames#{pri_node_name}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_pri_db_host#{self.pri_node.db_host}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_dataPortBase#{port}#g' {self.xml_path};" \
            f"sed -i 's#v_dataNode1#{data_node1},{sta_node_name}," \
            f"{data_node1}#g' {self.xml_path};" \
            f"sed -i 's#v_sta_nodeNames#{sta_node_name}#g' " \
            f"{self.xml_path};" \
            f"sed -i 's#v_sta_db_host#{self.sta_node.db_host}#g' " \
            f"{self.xml_path};" \
            f"cat {self.xml_path}"
        self.log.info(xml_cmd)
        result = self.common.get_sh_result(self.pri_root_node, xml_cmd)
        msg_list = [pri_node_name, self.pri_node.db_host,
                    sta_node_name, self.sta_node.db_host,
                    self.data_path, f"{port}"]
        for msg in msg_list:
            self.assertIn(msg, result, 'xml配置失败')
        self.assertNotIn('gaussdbLogPath', result, 'xml配置失败')

        self.log.info('-----step3:创建初始用户并修改密码 expect:创建成功-----')
        self.common.create_user(self.pri_root_node, self.u_name)
        self.common.create_user(self.sta_root_node, self.u_name)
        file_own = f'chown -R {self.u_name}:{self.u_name} ' \
            f'{self.dir_path};'
        self.log.info(file_own)
        file_msg = self.common.get_sh_result(self.pri_root_node, file_own)
        self.assertEqual('', file_msg, '文件属性修改失败')

        self.log.info('-----修改log文件夹权限 expect:成功-----')
        log_path = os.path.join(os.path.dirname(self.instance_path),
                                'var', 'log', 'gaussdb')
        file_own = f'chown {self.u_name}:{self.u_name} {log_path};'
        self.log.info(file_own)
        pri_file_msg = self.common.get_sh_result(self.pri_root_node, file_own)
        sta_file_msg = self.common.get_sh_result(self.sta_root_node, file_own)
        file_own2 = f'mkdir -p {log_path};' \
            f'chown {self.u_name}:{self.u_name} {log_path};'
        if 'No such file or directory' in pri_file_msg:
            self.log.info(file_own2)
            pri_file_msg = self.common.get_sh_result(self.pri_root_node,
                                                     file_own2)
        if 'No such file or directory' in sta_file_msg:
            self.log.info(file_own2)
            sta_file_msg = self.common.get_sh_result(self.sta_root_node,
                                                     file_own2)
        self.assertEqual('', pri_file_msg, '主机log修改失败')
        self.assertEqual('', sta_file_msg, '备机log修改失败')

        self.log.info('-----step4:执行gs_preinstall命令 expect:预安装成功-----')
        preinstall_cmd = f'./gs_preinstall -U {self.u_name} ' \
            f'-G {self.u_name} -X {self.xml_path}' \
            f' --sep-env-file={self.env_path} --skip-hostname-set '
        execute_cmd = f'''cd {self.script_path}
                       expect <<EOF
                       set timeout 2000
                       spawn {preinstall_cmd}
                       expect "*(yes/no)?"
                       send "no\\n"
                       expect "*(yes/no)?"
                       send "yes\\n"
                       expect "Password:"
                       send "{macro.COMMON_PASSWD}\\n"
                       expect eof\n''' + '''EOF'''
        self.log.info(execute_cmd)
        msg = self.common.get_sh_result(self.pri_root_node, execute_cmd)
        self.assertIn(Constant.preinstall_success_msg, msg, '预安装失败')

        self.log.info('-----step5:执行gs_install命令 expect:安装成功-----')
        su_cmd = f'su - {self.u_name}'
        install_cmd = f'gs_install -X {self.xml_path} ' \
            f'--dn-guc=shared_buffers=128MB'
        execute_cmd = f'''expect <<EOF
                       set timeout 600
                       spawn {su_cmd}
                       expect "$"
                       send "source {self.env_path}\\n"
                       expect "$"
                       send "{install_cmd}\\n"
                       expect "Please enter password for database:"
                       send "{macro.COMMON_PASSWD}\\n"
                       expect "Please repeat for database:"
                       send "{macro.COMMON_PASSWD}\\n"
                       expect eof\n''' + '''EOF'''
        self.log.info(execute_cmd)
        exec_msg = self.common.get_sh_result(self.pri_root_node, execute_cmd)
        self.assertIn(Constant.install_success_msg, exec_msg, '安装失败')

        self.log.info('-----step6:卸载数据库 expect:卸载成功,默认log路径无log文件-----')
        execute_cmd = f'su - {self.u_name} <<EOF\n' \
            f'source {self.env_path};' \
            f'gs_uninstall --delete-data;\n' \
            f'EOF'
        self.log.info(execute_cmd)
        msg = self.common.get_sh_result(self.pri_root_node, execute_cmd)
        self.assertIn(Constant.uninstall_success_msg, msg, '卸载失败')

        time.sleep(20)
        log_file = os.path.join(log_path, self.u_name, 'om')
        self.log.info(log_file)
        ls_cmd = f'ls {log_file}'
        msg = self.common.get_sh_result(self.pri_root_node, ls_cmd)
        assert1 = re.search(
            r"gs_uninstall-[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{6}.log", msg)
        self.log.info(assert1)
        self.assertIsNone(assert1, '卸载日志生成错误')

    def tearDown(self):
        self.log.info('-----step5:清理环境-----')
        self.log.info('-----删除用户下进程 expect:成功-----')
        kill_flag = False
        dir_flag = False
        user_flag = False
        log_flag = False
        kill_cmd = f"ps -u {self.u_name} | grep -v PID | " \
            f"awk \'{{{{print $1}}}}\' | xargs kill -9;" \
            f"ipcs -m|awk '{{{{if($3~/^[0-9]+$/) {{{{print $2}}}}}}}}'" \
            f" | xargs -I {{{{}}}} ipcrm -m {{{{}}}};" \
            f"ipcs -s|awk '{{{{if($3~/^[0-9]+$/) {{{{print $2}}}}}}}}'" \
            f" | xargs -I {{{{}}}} ipcrm -s {{{{}}}};sync;" \
            f"echo 3 > /proc/sys/vm/drop_caches"
        self.log.info(kill_cmd)
        for count in range(10):
            pri = self.common.get_sh_result(self.pri_root_node, kill_cmd)
            sta = self.common.get_sh_result(self.sta_root_node, kill_cmd)
            if pri and sta:
                self.log.info('process killed')
                kill_flag = True
                break
        self.log.info('-----删除用户及数据准备目录 expect:成功-----')
        check_cmd = f'rm -rf {self.dir_path};' \
            f'if [ -d {self.dir_path} ]; ' \
            f'then echo "exists"; else echo "not exists"; fi'
        self.log.info(check_cmd)
        for count in range(10):
            pri = self.common.get_sh_result(self.pri_root_node, check_cmd)
            sta = self.common.get_sh_result(self.sta_root_node, check_cmd)
            if 'not exists' in pri and 'not exists' in sta:
                self.log.info('file deleted')
                dir_flag = True
                break
        usr_cmd = f'userdel -rf {self.u_name};id {self.u_name}'
        for count in range(10):
            pri = self.common.get_sh_result(self.pri_root_node, usr_cmd)
            sta = self.common.get_sh_result(self.sta_root_node, usr_cmd)
            if 'no such user' in pri and 'no such user' in sta:
                self.log.info('user deleted')
                user_flag = True
                break
        del_cmd = f'chown root:root {log_path};' \
            f'rm -rf {os.path.join(log_path, self.u_name)};' \
            f'if [ -d {os.path.join(log_path, self.u_name)} ]; ' \
            f'then echo "exists"; else echo "not exists"; fi'
        for count in range(10):
            pri = self.common.get_sh_result(self.pri_root_node, del_cmd)
            sta1 = self.common.get_sh_result(self.sta_root_node, del_cmd)
            if 'not exists' in pri and 'not exists' in sta1:
                self.log.info('log deleted')
                log_flag = True
                break
        self.assertTrue(kill_flag, '清理环境失败')
        self.assertTrue(dir_flag, '清理环境失败')
        self.assertTrue(user_flag, '清理环境失败')
        self.assertTrue(log_flag, '清理环境失败')
        self.log.info(f'-----{os.path.basename(__file__)} finish-----')
